using System;
using System.Collections.Generic;
using System.Threading;
using Oracle.ManagedDataAccess.Client;
using OracleInternal.Common;
using OracleInternal.Network;
using OracleInternal.TTC;

namespace OracleInternal.ServiceObjects
{
	internal class OracleNotificationManager
	{
		internal delegate void SendNtfDetailsToUpperLayer(object obj);

		internal static NotificationListener m_ntfLsnr = NotificationListener.CreateListener();

		private static List<string> m_lstOfDbsRegd = new List<string>();

		internal static SendNtfDetailsToUpperLayer s_sendNtfDetailsToUpperLayer;

		private static object m_syncObjForMode = new object();

		internal static void StartListener(ref int portNo)
		{
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)262400, OracleTraceClassName.OracleNotificationManager, OracleTraceFuncName.StartListener);
			}
			m_ntfLsnr.Start(ref portNo);
		}

		internal static bool IsListenerRunning()
		{
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)262400, OracleTraceClassName.OracleNotificationManager, OracleTraceFuncName.IsListenerRunning);
			}
			try
			{
				return m_ntfLsnr.m_bListenerStarted;
			}
			catch (Exception ex)
			{
				OracleException.HandleError(OracleTraceLevel.Private, (OracleTraceTag)268697600, OracleTraceClassName.OracleNotificationManager, OracleTraceFuncName.IsListenerRunning, ex);
				throw;
			}
			finally
			{
				if (ProviderConfig.m_bTraceLevelPrivate)
				{
					Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)262656, OracleTraceClassName.OracleNotificationManager, OracleTraceFuncName.IsListenerRunning);
				}
			}
		}

		internal static void SetCallbackForNotification(SendNtfDetailsToUpperLayer callBackFn)
		{
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)262400, OracleTraceClassName.OracleNotificationManager, OracleTraceFuncName.SetCallbackForNotification);
			}
			s_sendNtfDetailsToUpperLayer = callBackFn;
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)262656, OracleTraceClassName.OracleNotificationManager, OracleTraceFuncName.SetCallbackForNotification);
			}
		}

		internal static void RegisterForChangeNotification(OracleConnectionImpl connectionImpl, OracleDependencyImpl orclDependencyImpl, bool bIncludeRowId)
		{
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)262400, OracleTraceClassName.OracleNotificationManager, OracleTraceFuncName.RegisterForChangeNotification);
			}
			try
			{
				bool flag = false;
				string text = null;
				_ = OracleDependencyImpl.s_machineAddress;
				if (ProviderConfig.m_bTraceLevelPrivate)
				{
					Trace.Write(OracleTraceLevel.Private, OracleTraceTag.SvcObj, OracleTraceClassName.OracleNotificationManager, OracleTraceFuncName.RegisterForChangeNotification, $"CAN use secure CQN for dependency:{orclDependencyImpl.m_guid} = {connectionImpl.m_bCanUseSecureCQN}");
				}
				if (!connectionImpl.m_bCanUseSecureCQN)
				{
					if (!IsListenerRunning())
					{
						int portNo = OracleDependencyImpl.m_portForlistening;
						StartListener(ref portNo);
						if (OracleDependencyImpl.m_portForlistening != portNo)
						{
							OracleDependencyImpl.m_portForlistening = portNo;
						}
					}
				}
				else
				{
					text = connectionImpl.m_pm.GetCQNListenerClientId();
					if (string.IsNullOrEmpty(text))
					{
						if (ProviderConfig.m_bTraceLevelPrivate)
						{
							Trace.Write(OracleTraceLevel.Private, OracleTraceTag.SvcObj, OracleTraceClassName.OracleNotificationManager, OracleTraceFuncName.RegisterForChangeNotification, $"Start NEW secure CIC for dependency:{orclDependencyImpl.m_guid}");
						}
						flag = true;
					}
					else if (ProviderConfig.m_bTraceLevelPrivate)
					{
						Trace.Write(OracleTraceLevel.Private, OracleTraceTag.SvcObj, OracleTraceClassName.OracleNotificationManager, OracleTraceFuncName.RegisterForChangeNotification, $"Use secure CIC with ClientId:{text} for dependency:{orclDependencyImpl.m_guid}");
					}
				}
				SendRegistrationInfo(connectionImpl, orclDependencyImpl, bIncludeRowId, text);
				orclDependencyImpl.m_bIsRegistered = true;
				if (ProviderConfig.m_bTraceLevelPrivate)
				{
					Trace.Write(OracleTraceLevel.Private, OracleTraceTag.SvcObj, OracleTraceClassName.OracleNotificationManager, OracleTraceFuncName.RegisterForChangeNotification, $"Dependency:{orclDependencyImpl.m_guid} registered with SvrRegId={orclDependencyImpl.m_RegIdFromServer}");
				}
				if (!connectionImpl.m_bCanUseSecureCQN)
				{
					return;
				}
				ClientInitiatedConnection clientInitiatedConnection = null;
				if (flag)
				{
					if (ProviderConfig.m_bTraceLevelPrivate)
					{
						Trace.Write(OracleTraceLevel.Private, OracleTraceTag.SvcObj, OracleTraceClassName.OracleNotificationManager, OracleTraceFuncName.RegisterForChangeNotification, $"Create CIC for CLIENT_ID: {orclDependencyImpl.m_clientId}");
					}
					try
					{
						clientInitiatedConnection = new ClientInitiatedConnection(orclDependencyImpl.m_clientId, connectionImpl.m_pm);
						clientInitiatedConnection.Connect();
					}
					catch (Exception)
					{
						try
						{
							UnRegisterFromChangeNotification(connectionImpl, orclDependencyImpl.m_RegIdFromServer, orclDependencyImpl.m_clientId);
						}
						catch (Exception ex)
						{
							if (ProviderConfig.m_bTraceLevelPrivate)
							{
								string str = $"Internal unregister call failed for registration-id:{orclDependencyImpl.m_RegIdFromServer} \n";
								str = str + "Exception Message: " + ex.Message;
								Trace.Write(OracleTraceLevel.Private, OracleTraceTag.SvcObj, OracleTraceClassName.OracleNotificationManager, OracleTraceFuncName.RegisterForChangeNotification, str);
							}
						}
						orclDependencyImpl.m_bIsRegistered = false;
						orclDependencyImpl.m_bIsEnabled = false;
						orclDependencyImpl.m_RegIdFromServer = 0;
					}
				}
				if (orclDependencyImpl.m_bIsRegistered)
				{
					if (ProviderConfig.m_bTraceLevelPrivate)
					{
						Trace.Write(OracleTraceLevel.Private, OracleTraceTag.SvcObj, OracleTraceClassName.OracleNotificationManager, OracleTraceFuncName.RegisterForChangeNotification, $"Add to s_serverIdToClientIdMap => {orclDependencyImpl.m_RegIdFromServer}={(int)orclDependencyImpl.m_clientRegistrationId}");
					}
					OracleDependency.s_serverIdToClientIdMap[orclDependencyImpl.m_RegIdFromServer] = (int)orclDependencyImpl.m_clientRegistrationId;
					connectionImpl.m_pm.AddCQNRestration(orclDependencyImpl.m_clientId, orclDependencyImpl.m_RegIdFromServer, clientInitiatedConnection);
				}
			}
			catch (Exception ex3)
			{
				OracleException.HandleError(OracleTraceLevel.Private, (OracleTraceTag)268697600, OracleTraceClassName.OracleNotificationManager, OracleTraceFuncName.RegisterForChangeNotification, ex3);
				throw;
			}
			finally
			{
				if (ProviderConfig.m_bTraceLevelPrivate)
				{
					Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)262656, OracleTraceClassName.OracleNotificationManager, OracleTraceFuncName.RegisterForChangeNotification);
				}
			}
		}

		private static void SendRegistrationInfo(OracleConnectionImpl connectionImpl, OracleDependencyImpl orclDependencyImpl, bool bIncludeRowId, string listenerClientId)
		{
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)262400, OracleTraceClassName.OracleNotificationManager, OracleTraceFuncName.SendRegistrationInfo);
			}
			int num = 0;
			try
			{
				string item = connectionImpl.m_databaseDomainName.Trim() + "|" + connectionImpl.m_databaseName.Trim();
				int mode = 0;
				if (connectionImpl.m_bCanUseSecureCQN)
				{
					mode = 4;
				}
				else
				{
					if (OracleDependencyImpl.m_bIsAddressConfigured)
					{
						mode = 2;
					}
					if (!m_lstOfDbsRegd.Contains(item))
					{
						lock (m_syncObjForMode)
						{
							if (!m_lstOfDbsRegd.Contains(item))
							{
								mode = ((!OracleDependencyImpl.m_bIsAddressConfigured) ? 1 : 3);
								m_lstOfDbsRegd.Add(item);
							}
						}
					}
				}
				if (orclDependencyImpl.m_bQueryBasedNTFN)
				{
					num = 96;
				}
				if (bIncludeRowId)
				{
					num |= 0x10;
				}
				int num2 = 0;
				if (connectionImpl.m_bCanUseSecureCQN)
				{
					num2 = 522;
				}
				if (!connectionImpl.m_bCanUseSecureCQN && orclDependencyImpl.m_bIsPersistent)
				{
					num2 = 1;
				}
				if (orclDependencyImpl.m_bIsNotifiedOnce)
				{
					num2 |= 0x10;
				}
				int[] nameSpace = new int[1]
				{
					2
				};
				string[] registeredAgentName = new string[1];
				int[] payloadType = new int[1]
				{
					23
				};
				int[] qosFlags = new int[1]
				{
					num2
				};
				int[] timeout = new int[1]
				{
					(int)orclDependencyImpl.m_timeout
				};
				int[] dbchangeOpFilter = new int[1]
				{
					num
				};
				int[] dbchangeTxnLag = new int[1];
				int[] dbchangeRegistrationId = new int[1];
				byte[][] array = new byte[1][]
				{
					new byte[4]
				};
				array[0][0] = (byte)((orclDependencyImpl.m_clientRegistrationId & 0xFF000000u) >> 24);
				array[0][1] = (byte)((orclDependencyImpl.m_clientRegistrationId & 0xFF0000) >> 16);
				array[0][2] = (byte)((orclDependencyImpl.m_clientRegistrationId & 0xFF00) >> 8);
				array[0][3] = (byte)(orclDependencyImpl.m_clientRegistrationId & 0xFF);
				string text = null;
				text = ((!connectionImpl.m_bCanUseSecureCQN) ? ("(ADDRESS=(PROTOCOL=tcp)(HOST=" + OracleDependencyImpl.s_machineAddress + ")(PORT=" + OracleDependencyImpl.m_portForlistening + "))?PR=0") : listenerClientId);
				try
				{
					connectionImpl.m_connectionFreeToUseEvent.WaitOne();
					connectionImpl.AddAllPiggyBackRequests();
					TTCNotification tTCNotificationObject = connectionImpl.TTCNotificationObject;
					tTCNotificationObject.WriteOKPNMessage(1, mode, connectionImpl.m_cs.m_userId, text, 1, nameSpace, registeredAgentName, array, payloadType, qosFlags, timeout, dbchangeOpFilter, dbchangeTxnLag, dbchangeRegistrationId);
					tTCNotificationObject.ReceiveOKPNResponse();
					orclDependencyImpl.m_RegIdFromServer = tTCNotificationObject.m_registrationId;
					orclDependencyImpl.m_clientId = (string.IsNullOrEmpty(tTCNotificationObject.m_clientId) ? listenerClientId : tTCNotificationObject.m_clientId);
					orclDependencyImpl.m_listenerAddress = tTCNotificationObject.m_listenerAddress;
					OracleConnectionImpl.CheckForAnyErrorFromDB(connectionImpl.m_marshallingEngine.TTCErrorObject);
				}
				finally
				{
					connectionImpl.m_connectionFreeToUseEvent.Set();
				}
			}
			catch (Exception ex)
			{
				OracleException.HandleError(OracleTraceLevel.Private, (OracleTraceTag)268697600, OracleTraceClassName.OracleNotificationManager, OracleTraceFuncName.SendRegistrationInfo, ex);
				throw;
			}
			finally
			{
				if (ProviderConfig.m_bTraceLevelPrivate)
				{
					Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)262656, OracleTraceClassName.OracleNotificationManager, OracleTraceFuncName.SendRegistrationInfo);
				}
			}
		}

		internal static void UnRegisterFromChangeNotification(OracleConnectionImpl connectionImpl, int dbChangeRegistrationId, string listenerClientId)
		{
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)262400, OracleTraceClassName.OracleNotificationManager, OracleTraceFuncName.UnRegisterFromChangeNotification);
			}
			try
			{
				int[] nameSpace = new int[1]
				{
					2
				};
				string[] registeredAgentName = new string[1];
				int[] payloadType = new int[1];
				int[] qosFlags = new int[1];
				int[] timeout = new int[1];
				int[] dbchangeOpFilter = new int[1];
				int[] dbchangeTxnLag = new int[1];
				int[] dbchangeRegistrationId = new int[1]
				{
					dbChangeRegistrationId
				};
				byte[][] kpdnrcx = new byte[1][];
				string text = "";
				text = ((!connectionImpl.m_bCanUseSecureCQN) ? ("(ADDRESS=(PROTOCOL=tcp)(HOST=" + OracleDependencyImpl.s_machineAddress + ")(PORT=" + OracleDependencyImpl.m_portForlistening + "))?PR=0") : listenerClientId);
				try
				{
					connectionImpl.m_connectionFreeToUseEvent.WaitOne();
					connectionImpl.AddAllPiggyBackRequests();
					TTCNotification tTCNotificationObject = connectionImpl.TTCNotificationObject;
					tTCNotificationObject.WriteOKPNMessage(2, OracleDependencyImpl.m_bIsAddressConfigured ? 2 : 0, null, text, 1, nameSpace, registeredAgentName, kpdnrcx, payloadType, qosFlags, timeout, dbchangeOpFilter, dbchangeTxnLag, dbchangeRegistrationId);
					tTCNotificationObject.ReceiveOKPNResponse();
					OracleConnectionImpl.CheckForAnyErrorFromDB(connectionImpl.m_marshallingEngine.TTCErrorObject);
				}
				finally
				{
					connectionImpl.m_connectionFreeToUseEvent.Set();
					connectionImpl.m_pm.RemoveCQNRestration(listenerClientId, dbChangeRegistrationId);
				}
			}
			catch (Exception ex)
			{
				OracleException.HandleError(OracleTraceLevel.Private, (OracleTraceTag)268697600, OracleTraceClassName.OracleNotificationManager, OracleTraceFuncName.UnRegisterFromChangeNotification, ex);
				throw;
			}
			finally
			{
				if (ProviderConfig.m_bTraceLevelPrivate)
				{
					Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)262656, OracleTraceClassName.OracleNotificationManager, OracleTraceFuncName.UnRegisterFromChangeNotification);
				}
			}
		}

		internal static void HandleNotification(OracleCommunication dataEP)
		{
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)262400, OracleTraceClassName.OracleNotificationManager, OracleTraceFuncName.HandleNotification);
			}
			try
			{
				Thread thread = new Thread(new ThreadStart(new NotificationHandler(dataEP).ProcessNotification));
				thread.IsBackground = true;
				thread.Start();
			}
			catch (Exception ex)
			{
				OracleException.HandleError(OracleTraceLevel.Private, (OracleTraceTag)268697600, OracleTraceClassName.OracleNotificationManager, OracleTraceFuncName.HandleNotification, ex);
			}
			finally
			{
				if (ProviderConfig.m_bTraceLevelPrivate)
				{
					Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)262656, OracleTraceClassName.OracleNotificationManager, OracleTraceFuncName.HandleNotification);
				}
			}
		}
	}
}
